package com.ubxtech.nacos.listener;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.ubxtech.balance.util.ServiceInstanceUtil;
import com.ubxtech.core.utils.SpringUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;


/**
 * https://blog.csdn.net/wangshuai6707/article/details/134666101
 * @author Victor.Xiao
 * @since 2023-12-11 20:46
 **/
@Slf4j
public class ServiceDiscoveryListenerBuilder {
    //key是serviceName,map<String,Boolean> key是服务id,或者是ip加端口组合,boolean是代表是否上线
    protected static Map<String, Map<String, Boolean>> instanceHealthStatus = new ConcurrentHashMap<>();

    public static EventListener buildEventListener() {
        return event -> {
            if (event instanceof NamingEvent) {
                NamingEvent namingEvent = (NamingEvent) event;
                String serviceName = namingEvent.getServiceName();
                ServiceDiscoveryListenerBuilder.repeatDiscoveryListener(serviceName, ((NamingEvent) event).getInstances());
            }
        };
    }


    /**
     *
     * @author Victor.Xiao
     * @since 2023-12-12 16:42
     * @param serviceName serviceName
     * @param instances instances
    */
    public static void repeatDiscoveryListener(String serviceName ,List<Instance> instances) {
        if (log.isDebugEnabled()) {
            log.debug("服务实例变化:{}", JSONObject.toJSONString(instances));
        }
        //变化结果
        List<ServiceStatusEventDTO> serviceStatusEventDTOS = new ArrayList<>();
        //处理已经存在的服务列表和对应的状态
        Map<String, Boolean> oldServiceStatusMap = instanceHealthStatus.computeIfAbsent(serviceName, k -> new ConcurrentHashMap<>());
        Map<String, Instance> instanceMap = new ConcurrentHashMap<>();
//      Map<String,Instance> instanceMap = instances.stream().collect(Collectors.toMap(ServiceInstanceUtil::getServiceId, a -> a,(k1, k2)->k1));
        //当前服务状态
        Map<String, Boolean> newServiceStatusMap = new ConcurrentHashMap<>();
        for (Instance instance : instances) {
            String instanceServiceId =  ServiceInstanceUtil.getServiceId(instance);
            newServiceStatusMap.put(instanceServiceId,instance.isHealthy() && instance.isEnabled());
            instanceMap.put(instanceServiceId, instance);
        }
        if (log.isDebugEnabled()) {
            log.debug("最新服务状态:{}",newServiceStatusMap);
            log.debug("已有的服务状态:{}",oldServiceStatusMap);
        }
        //新的服务id
        Set<String> newServiceIds = instanceMap.keySet();
        //现有的服务id
        Set<String> oldServiceIds = new HashSet<>(oldServiceStatusMap.keySet());
        //新的减去旧的,就是新上线的服务
        Collection<String> newSubServiceIds = CollectionUtil.subtract(newServiceIds, oldServiceIds);
        if (log.isDebugEnabled()) {
            log.debug("新上线的服务:{}",newSubServiceIds);
        }
        for (String subId : newSubServiceIds) {
            //下线
            if (!newServiceStatusMap.getOrDefault(subId,false)) {
                serviceStatusEventDTOS.add(createServiceStatusEventDTO(subId,serviceName,0));
            }
            else {
                serviceStatusEventDTOS.add(createServiceStatusEventDTO(subId,serviceName,1));
            }
        }
        // 下线实例,旧的减去新的
        Collection<String> downSubServiceIds = CollectionUtil.subtract(oldServiceIds, newServiceIds);
        if (log.isDebugEnabled()) {
            log.debug("新下线的服务:{}",downSubServiceIds);
        }
        for (String subId : downSubServiceIds) {
            serviceStatusEventDTOS.add(createServiceStatusEventDTO(subId,serviceName,0));
        }
        // 都存在,可能状态有变化
        Collection<String> bothSubServiceIds = CollectionUtil.intersectionDistinct(oldServiceIds, newServiceIds);
        if (log.isDebugEnabled()) {
            log.debug("有状态变化的服务:{}",bothSubServiceIds);
        }
        for (String bothSubServiceId : bothSubServiceIds) {
            boolean newHealthy = newServiceStatusMap.getOrDefault(bothSubServiceId,false);
            boolean oldHealthy = oldServiceStatusMap.getOrDefault(bothSubServiceId,false);
            //相等不处理
            if (newHealthy == oldHealthy) {
                continue;
            }
            //下线
            if (newHealthy) {
                serviceStatusEventDTOS.add(createServiceStatusEventDTO(bothSubServiceId,serviceName,0));
            }
            else {
                serviceStatusEventDTOS.add(createServiceStatusEventDTO(bothSubServiceId,serviceName,1));
            }
        }
        oldServiceStatusMap.clear();
        oldServiceStatusMap.putAll(newServiceStatusMap);
        if (serviceStatusEventDTOS.size() > 0) {
            log.info("最终推送服务状态结果:{}",serviceStatusEventDTOS);
            for (ServiceStatusEventDTO serviceStatusEventDTO : serviceStatusEventDTOS) {
                SpringUtils.publishEvent(serviceStatusEventDTO);
            }
        }
    }

    public static ServiceStatusEventDTO createServiceStatusEventDTO(String serviceId,String serviceName,Integer status) {
        ServiceStatusEventDTO serviceStatusEventDTO = new ServiceStatusEventDTO();
        serviceStatusEventDTO.setServiceId(serviceId);
        serviceStatusEventDTO.setServiceName(serviceName);
        serviceStatusEventDTO.setStatus(status);
        return serviceStatusEventDTO;
    }

}
